package com.train.mgr.modules.biz.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.train.common.model.PageResult;
import com.train.mgr.modules.biz.dto.request.StatQueryDTO;
import com.train.mgr.modules.biz.entity.*;
import com.train.mgr.modules.biz.mapper.StatCourseTraineeMapper;
import com.train.mgr.modules.biz.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 课程学员学习统计表 服务实现类
 * </p>
 *
 * @author cxg
 * @date 2025-10-11
 */
@Slf4j
@RequiredArgsConstructor
@Service("IStatCourseTraineeService")
public class StatCourseTraineeServiceImpl extends ServiceImpl<StatCourseTraineeMapper, StatCourseTrainee> implements IStatCourseTraineeService {

    private final ICourseUserService courseUserService;
    private final ICourseService courseService;
    private final IStatLessonTraineeService statLessonTraineeService;
    private final ICourseStuGroupService courseStuGroupService;
    @Override
    public PageResult<StatCourseTrainee> courseTraineeList(StatQueryDTO params){
        Page<StatCourseTrainee> page = params.buildPage();
        LambdaQueryWrapper<StatCourseTrainee> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.and(
                StrUtil.isNotBlank(params.getQ()),
                wrapper -> wrapper.like(StatCourseTrainee::getNickName, params.getQ())
                        .or()
                        .like(StatCourseTrainee::getUsername, params.getQ())
        );
        queryWrapper.eq(StatCourseTrainee::getCourseId,params.getCourseId());
        queryWrapper.eq(params.getGroupId()!=null && params.getGroupId() >0,StatCourseTrainee::getGroupId,params.getGroupId());
        queryWrapper.orderByAsc(StatCourseTrainee::getJoinTime);
        Page<StatCourseTrainee> resultPage = baseMapper.selectPage(page, queryWrapper);
        return PageResult.of(resultPage, StatCourseTrainee.class);
    }

    @Override
    public void buildLessonTraineeStat(String courseId) {
        List<StatCourseTrainee> stats = new ArrayList<>();
        UpdateWrapper<StatCourseTrainee> updateWrapper = new UpdateWrapper<>();
        updateWrapper.ne(StrUtil.isBlank(courseId),"id", 0L);
        updateWrapper.eq(StrUtil.isNotBlank(courseId),"course_id", courseId);
        baseMapper.delete(updateWrapper);
        List<Course> courseList;
        if (StrUtil.isBlank(courseId)){
            courseList = courseService.getCourseList();
        } else {
            Course course = courseService.getById(courseId);
            courseList = Collections.singletonList(course);
        }
        for (Course course : courseList) {
            LambdaQueryWrapper<CourseUser> eq = new LambdaQueryWrapper<CourseUser>()
                    .eq(CourseUser::getCourseId, course.getId())
                    .eq(CourseUser::getIsDeleted, 0);
            List<CourseUser> courseUserList = courseUserService.list(eq);
            courseUserList.forEach(courseUser -> {
                LambdaQueryWrapper<StatLessonTrainee> queryWrapper = new LambdaQueryWrapper<StatLessonTrainee>()
                        .eq(StatLessonTrainee::getCourseId, course.getId())
                        .eq(StatLessonTrainee::getUsername, courseUser.getUserName())
                        .eq(StatLessonTrainee::getIsDeleted, 0);
                List<StatLessonTrainee> list = statLessonTraineeService.list(queryWrapper);
                if (CollUtil.isEmpty(list)){
                    CourseStuGroup group = courseStuGroupService.selectGroupIdByUser(courseUser.getCourseId(), courseUser.getUserId());
                    Long groupId = group == null ? 0L : group.getId();
                    StatCourseTrainee statCourseTrainee = new StatCourseTrainee();
                    statCourseTrainee.setCourseId(course.getId());
                    statCourseTrainee.setCustomerId(course.getCustomerId());
                    statCourseTrainee.setGroupId(groupId);
                    statCourseTrainee.setNickName(courseUser.getNickName());
                    statCourseTrainee.setUsername(courseUser.getUserName());
                    statCourseTrainee.setCourseFinishRate("0");
                    statCourseTrainee.setCourseOverallScore(BigDecimal.ZERO);
                    statCourseTrainee.setCourseLearnDuration(BigDecimal.ZERO);
                    statCourseTrainee.setCourseExercisesNum(0);
                    statCourseTrainee.setReadRepeatedTimes(0);
                    statCourseTrainee.setReadAvgScore(BigDecimal.ZERO);
                    statCourseTrainee.setReadMaxScore(BigDecimal.ZERO);
                    statCourseTrainee.setReadPassRate("0");
                    stats.add(statCourseTrainee);
                    return;
                }
                Map<String, List<StatLessonTrainee>> collect = list.stream().collect(Collectors.groupingBy(StatLessonTrainee::getUsername));
                collect.forEach((username, statLessonTrainees) -> {
                    StatLessonTrainee statLessonTrainee = statLessonTrainees.get(0);
                    StatCourseTrainee statCourseTrainee = new StatCourseTrainee();
                    statCourseTrainee.setCourseId(course.getId());
                    statCourseTrainee.setCustomerId(course.getCustomerId());
                    statCourseTrainee.setGroupId(statLessonTrainee.getGroupId());
                    statCourseTrainee.setNickName(courseUser.getNickName());
                    statCourseTrainee.setUsername(statLessonTrainee.getUsername());
                    statCourseTrainee.setJoinTime(DateUtil.format(courseUser.getJoinTime(), "yyyy-MM-dd HH:mm:ss"));
                    statCourseTrainee.setFinishTime(DateUtil.format(courseUser.getFinishTime(), "yyyy-MM-dd HH:mm:ss"));
                    long count = list.stream().filter(x -> x.getLessonFinishState() != null && x.getLessonFinishState().equals("1")).count();
                    BigDecimal courseFinishRate = new BigDecimal(count).multiply(BigDecimal.valueOf(100).divide(new BigDecimal(list.size()),1, RoundingMode.HALF_UP));
                    if (courseFinishRate.compareTo(BigDecimal.ZERO) == 0){
                        statCourseTrainee.setCourseFinishRate("0");
                    } else if (courseFinishRate.compareTo(BigDecimal.valueOf(100)) == 0){
                        statCourseTrainee.setCourseFinishRate("100");
                    } else {
                        statCourseTrainee.setCourseFinishRate(courseFinishRate.toPlainString().replace(".000", ""));
                    }
                    // 个人练习次数
                    long exercisesNum = list.stream().filter(x -> x.getLessonExercisesNum() != null && x.getLessonExercisesNum() > 0).count();
                    BigDecimal rate = BigDecimal.ZERO;
                    BigDecimal finalReadPassRateTemp = BigDecimal.ZERO;
                    for (StatLessonTrainee lessonTrainee : list) {
                        String readPassRate = lessonTrainee.getReadPassRate();
                        if (StrUtil.isNotBlank(readPassRate)){
                            String replace = readPassRate.replace("%", "");
                            finalReadPassRateTemp = finalReadPassRateTemp.add(new BigDecimal(replace));
                        }
                    }
                    if (exercisesNum == 0){
                        statCourseTrainee.setCourseOverallScore(BigDecimal.ZERO);
                        statCourseTrainee.setReadAvgScore(BigDecimal.ZERO);
                    } else {
                        statCourseTrainee.setReadAvgScore(list.stream().map(StatLessonTrainee::getReadAvgScore).reduce(BigDecimal.ZERO, BigDecimal::add).divide(new BigDecimal(exercisesNum),1, RoundingMode.HALF_UP));
                        rate = finalReadPassRateTemp.divide(new BigDecimal(exercisesNum), 1, RoundingMode.HALF_UP);
                    }
                    BigDecimal maxReadScore = list.stream().map(StatLessonTrainee::getReadMaxScore).reduce(BigDecimal.ZERO,BigDecimal::add);
                    long count1 = list.stream().filter(x -> username.equals(x.getUsername())).count();
                    statCourseTrainee.setReadMaxScore(maxReadScore.divide(new BigDecimal(count1),1, RoundingMode.HALF_UP));
                    BigDecimal divide = list.stream().map(StatLessonTrainee::getLessonOverallScore).reduce(BigDecimal.ZERO, BigDecimal::add).divide(new BigDecimal(count1),2, RoundingMode.HALF_UP);
                    statCourseTrainee.setCourseOverallScore(divide.setScale(1, RoundingMode.HALF_UP));
                    statCourseTrainee.setCourseLearnDuration(list.stream().map(StatLessonTrainee::getLessonLearnDuration).reduce(BigDecimal.ZERO, BigDecimal::add));
                    statCourseTrainee.setCourseExercisesNum(list.stream().mapToInt(StatLessonTrainee::getLessonExercisesNum).sum());
                    statCourseTrainee.setReadRepeatedTimes(list.stream().mapToInt(StatLessonTrainee::getReadRepeatedTimes).sum());


                    if (rate.compareTo(BigDecimal.ZERO) == 0){
                        statCourseTrainee.setReadPassRate("0");
                    } else if (rate.compareTo(BigDecimal.valueOf(100)) == 0) {
                        statCourseTrainee.setReadPassRate("100");
                    } else {
                        statCourseTrainee.setReadPassRate(rate.toPlainString().replace(".000", "") );
                    }
                    stats.add(statCourseTrainee);
                });
            });
        }
        if (CollUtil.isNotEmpty(stats)){
            saveBatch(stats);
        }
    }

}
